<?php
// +----------------------------------------------------------------------
// | Author: July
// +----------------------------------------------------------------------
// | 创建时间: 2023-12-27 20:39:42
// +----------------------------------------------------------------------
// | 菜单相关操作
// +----------------------------------------------------------------------

namespace july\julyadmin\common\logic;

class MenuLogic
{
    //上下文对象
    public $context;

    /**
     * 初始化
     * @param class $context 上下文对象，也就是调用当前类的this，通常传递$this即可
     */
    public function __construct($context)
    {
        $this->context = $context;
    }

    /**
     * 获取可用权限下拉列表
     * @Author   July
     * @DateTime 2024-01-13T20:10:57+0800
     * @return array
     */
    public function getPermissionsSelect()
    {
        //从julyadmin获取控制器和权限
        $files = [];
        $files = $this->getControllers('../vendor/july/julyadmin/src/admin', $files, '【系统菜单】');
        $data  = [];
        if ($files) {
            $data[] = ['id' => 'group_' . count($data), 'text' => '【系统菜单】', 'disabled' => true];
            $data   = array_merge($data, $files);
        }

        //查询app目录下的所有控制器和权限
        $files = [];
        $files = $this->getControllers('../app', $files, '【用户模块】');
        if ($files) {
            $data[] = ['id' => 'group_' . count($data), 'text' => '【用户模块】', [], 'disabled' => true];
            $data   = array_merge($data, $files);
        }
        $data = array_values($data);

        //查询extend目录下的所有插件控制器和权限
        $helpers = $this->getExtendHelpers();
        foreach ($helpers as $helper_k => $helper) {
            if ($helper['adminModules']) {
                foreach ($helper['adminModules'] as $mk => $module) {
                    $files = [];
                    $files = $this->getControllers('../extend/' . $helper['package'] . '/' . $module, $files, '【插件' . $helper['package'] . '】');
                    if ($files) {
                        $data[] = ['id' => 'group_' . count($data), 'text' => '【插件' . $helper['package'] . '】', 'disabled' => true];
                        $data   = array_merge($data, $files);
                    }
                    $data = array_values($data);
                }

            }
        }
        return $data;
    }

    /**
     * 获取控制器数组
     * @Author   July
     * @DateTime 2024-01-13T20:11:18+0800
     * @param string $dir          控制器目录
     * @param array  $files        控制器文件数组
     * @param string $代码来源      系统菜单，还是插件，还是app
     * @return array
     */
    public function getControllers($dir = "", &$files = [], $source = '')
    {
        $handle = opendir($dir);
        while ($file = readdir($handle)) {
            $type = filetype($dir . "/" . $file);
            if ($file == '.' || $file == "..") {
                continue;
            }

            if ($type == "file") {
                //如果类型为文件
                $source_file = $dir . "/" . $file;
                $ext         = explode(".", $file);
                if (count($ext) > 1) {
                    if ($ext[count($ext) - 1] == "php" && stripos($dir, "controller") > -1) {
                        //从找到的控制器中匹配出命名空间
                        $code = file_get_contents($source_file);
                        //替换掉控制器文件中的所有注释，避免下面获取权限按钮的时候获取到注释掉的权限按钮v
                        //删除EOT块
                        $code = preg_replace('/<<<EOT[\s\S]*?EOT;/s', '', $code);
                        //删除<script>块
                        $code = preg_replace('/<script[\s\S]*?<\/script>/s', '', $code);
                        //删除<style>块
                        $code = preg_replace('/<style[\s\S]*?<\/style>/s', '', $code);
                        //删除块注释
                        $code = preg_replace('/\/\*\*[\s\S]*?\*\//s', '', $code);
                        //删除行注释
                        $code = preg_replace('~//(.*)+\n~', '', $code);
                        //删除items这里的->show，避免被误判加进来
                        $code = preg_replace('/->show\([\'items\'|\"items\"](.*?)/s', '', $code);
                        //找到命名空间
                        $preg = '~namespace ([a-zA-Z\\\]+)~';
                        preg_match_all($preg, $code, $namespaceRes);
                        if (isset($namespaceRes[1][0]) && $namespaceRes[1][0]) {
                            //匹配出class名称，如果class名称不为空就记录到数组
                            $preg = '~class ([a-zA-Z\\\]+)~';
                            preg_match_all($preg, $code, $classRes);
                            if (isset($classRes[1][0]) && $classRes[1][0]) {
                                $modulePreg = '~\\\([a-zA-Z0-9]+)\\\controller~';
                                preg_match_all($modulePreg, $namespaceRes[1][0], $moduleRes);
                                $module     = $moduleRes[1][0];
                                $controller = $classRes[1][0];
                                $files[]    = ['id' => "{$module}\\{$controller}", 'text' => "\\{$module}\\{$controller}{$source}", 'disabled' => true];
                                //判断index方法是否存在，如果存在则加入到列表
                                $control = $namespaceRes[1][0] . "\\" . $classRes[1][0];
                                if (class_exists($control) && method_exists($control, 'index')) {
                                    $files[] = ['id' => "{$module}\\{$controller}\\index", 'text' => '├─' . "{$module}\\{$controller}\\index" . '[首页]'];
                                }
                                //通过正则表达式，匹配出控制器中的权限按钮，并进行拼装
                                $preg = '~((->addBtn|->editBtn|->deleteBtn|->disabledBtn|->linkBtn|->openWindowBtn|->viewBtn|->show)\(.*\))~';
                                preg_match_all($preg, $code, $res);
                                if (isset($res[2]) && $res[2]) {
                                    foreach ($res[2] as $bk => $bv) {
                                        $params_preg = '~\((.*)\)~';
                                        preg_match_all($params_preg, $res[0][$bk], $params_res);
                                        $btn    = [];
                                        $params = array_filter(explode(',', $params_res[1][0]));
                                        $bv     = explode('->', $bv)[1];
                                        if (in_array($bv, ['addBtn', 'editBtn', 'disabledBtn', 'deleteBtn', 'show'])) {
                                            switch ($bv) {
                                                //如果是添加按钮
                                                case 'addBtn':
                                                    $control = $namespaceRes[1][0] . "\\" . $classRes[1][0];
                                                    if (class_exists($control) && method_exists($control, 'add')) {
                                                        $btn['id'] = "{$module}\\{$controller}\\add";
                                                        if (isset($params[1]) && $bv != 'show') {
                                                            $btn['text'] = trim(trim($params[1]), "'");
                                                            $btn['text'] = trim(trim($btn['text']), '"');
                                                            if ($btn['text'] == 'null') {
                                                                $btn['text'] = $this->context->addText;
                                                            }
                                                            $btn['text'] = '├─' . $btn['id'] . '[' . $btn['text'] . ']';
                                                        } else if (!isset($btn['text'])) {
                                                            $btn['text'] = '├─' . $btn['id'] . '[' . $this->context->addText . ']';
                                                        }
                                                    }

                                                    break;
                                                case 'editBtn':
                                                    //如果是编辑按钮
                                                    $control = $namespaceRes[1][0] . "\\" . $classRes[1][0];
                                                    if (class_exists($control) && method_exists($control, 'edit')) {
                                                        $btn['id'] = "{$module}\\{$controller}\\edit";
                                                        if (isset($params[1]) && $bv != 'show') {
                                                            $btn['text'] = trim(trim($params[1]), "'");
                                                            $btn['text'] = trim(trim($btn['text']), '"');
                                                            if ($btn['text'] == 'null') {
                                                                $btn['text'] = $this->context->editText;
                                                            }
                                                            $btn['text'] = '├─' . $btn['id'] . '[' . $btn['text'] . ']';
                                                        } else if (!isset($btn['text'])) {
                                                            $btn['text'] = '├─' . $btn['id'] . '[' . $this->context->editText . ']';
                                                        }
                                                    }
                                                    break;
                                                case 'deleteBtn':
                                                    //如果是删除按钮
                                                    $control = $namespaceRes[1][0] . "\\" . $classRes[1][0];
                                                    if (class_exists($control) && method_exists($control, 'delete')) {
                                                        $btn['id'] = "{$module}\\{$controller}\\delete";
                                                        if (isset($params[1]) && $bv != 'show') {
                                                            $btn['text'] = trim(trim($params[1]), "'");
                                                            $btn['text'] = trim(trim($btn['text']), '"');
                                                            if ($btn['text'] == 'null') {
                                                                $btn['text'] = $this->context->deleteText;
                                                            }
                                                            $btn['text'] = '├─' . $btn['id'] . '[' . $btn['text'] . ']';
                                                        } else if (!isset($btn['text'])) {
                                                            $btn['text'] = '├─' . $btn['id'] . '[' . $this->context->deleteText . ']';
                                                        }
                                                    }
                                                    break;
                                                case 'disabledBtn':
                                                    //如果是禁用开启按钮
                                                    $control = $namespaceRes[1][0] . "\\" . $classRes[1][0];
                                                    if (class_exists($control) && method_exists($control, 'disabled')) {
                                                        $btn['id'] = "{$module}\\{$controller}\\disabled";
                                                        if (isset($params[1]) && $bv != 'show') {
                                                            $btn['text'] = trim(trim($params[1]), "'");
                                                            $btn['text'] = trim(trim($btn['text']), '"');
                                                            if ($btn['text'] == 'null') {
                                                                $btn['text'] = $this->context->disabledText;
                                                            }
                                                            $btn['text'] = '├─' . $btn['id'] . '[' . $btn['text'] . ']';
                                                        } else if (!isset($btn['text'])) {
                                                            $btn['text'] = '├─' . $btn['id'] . '[' . $this->context->disabledText . ']';
                                                        }
                                                    }
                                                    break;
                                                case 'viewBtn':
                                                    //如果是详情按钮
                                                    $control = $namespaceRes[1][0] . "\\" . $classRes[1][0];
                                                    if (class_exists($control) && method_exists($control, 'view')) {
                                                        $btn['id'] = "{$module}\\{$controller}\\view";
                                                        if (isset($params[1]) && $bv != 'show') {
                                                            $btn['text'] = trim(trim($params[1]), "'");
                                                            $btn['text'] = trim(trim($btn['text']), '"');
                                                            if ($btn['text'] == 'null') {
                                                                $btn['text'] = $this->context->ViewText;
                                                            }
                                                            $btn['text'] = '├─' . $btn['id'] . '[' . $btn['text'] . ']';
                                                        } else if (!isset($btn['text'])) {
                                                            $btn['text'] = '├─' . $btn['id'] . '[' . $this->context->ViewText . ']';
                                                        }
                                                    }
                                                    break;
                                                case 'show':
                                                    //如果是表格编辑
                                                    $control = $namespaceRes[1][0] . "\\" . $classRes[1][0];
                                                    if (class_exists($control) && method_exists($control, 'autopost')) {
                                                        if (isset($params[2]) && $params[2] && $params[0] != 'image') {
                                                            $btn['id']   = "{$module}\\{$controller}\\autopost";
                                                            $btn['text'] = $btn['text'] = '├─' . $btn['id'] . '[表格自动保存]';
                                                        }
                                                    }
                                                    break;
                                            }
                                        } else if (in_array($bv, ['linkBtn', 'openWindowBtn'])) {
                                            //如果是链接按钮或者打开窗口按钮
                                            if (isset($params[0])) {
                                                $action    = trim($params[0], "'");
                                                $action    = trim($action, '"');
                                                $btn['id'] = "{$module}\\{$controller}\\{$action}";
                                            }
                                            if (isset($params[1])) {
                                                $btn['text'] = trim(trim($params[1]), "'");
                                                $btn['text'] = trim(trim($btn['text']), '"');
                                                $btn['text'] = '├─' . $btn['id'] . '[' . $btn['text'] . ']';
                                            }
                                        }

                                        //如果按钮不为空
                                        if ($btn) {
                                            //判断按钮是否已经添加到节点中
                                            $is_exis = false;
                                            foreach ($files as $ck => $cv) {
                                                if ($cv['id'] == $btn['id']) {
                                                    $is_exis = true;
                                                }
                                            }
                                            //如果按钮没有重复则添加到节点中
                                            if (!$is_exis) {
                                                $files[] = $btn;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if ($type == "dir") {
                //如果类型为文件夹
                $this->getControllers($dir . DIRECTORY_SEPARATOR . $file, $files, $source);
            }
        }
        closedir($handle);
        return $files;
    }

    /**
     * 递归获取extend目录下的所有helpers文件内容
     * @Author   July
     * @DateTime 2024-01-13T10:11:25+0800
     * @param    string                   $extend_path extend目录
     * @param    array                    &$helpers    helper列表
     * @return   array                                 helper列表
     */
    private function getExtendHelpers($extend_path = '', &$helpers = [])
    {
        if (!$extend_path) {
            $extend_path = app()->getRootPath() . 'extend';
        }

        $handle = opendir($extend_path);
        while ($file = readdir($handle)) {
            if ($file == '.' || $file == "..") {
                continue;
            }

            $temp = explode('.', $file);
            if ($file == 'helper.php') {
                $helpers[] = include $extend_path . "/" . $file;
            }
            if (is_dir($extend_path . DIRECTORY_SEPARATOR . $file)) {
                $this->getExtendHelpers($extend_path . DIRECTORY_SEPARATOR . $file, $helpers);
            }
        }
        closedir($handle);

        return $helpers;
    }
}
